package com.iakuil.mvp.mp.service;

import com.iakuil.mvp.mp.common.constant.RedisConstant;
import com.iakuil.mvp.mp.common.constant.WxConstant;
import com.iakuil.mvp.mp.config.WxSettings;
import com.iakuil.mvp.mp.dto.wx.AccessToken;
import com.iakuil.mvp.mp.dto.wx.SessionKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 小程序Token及SessionKey服务
 */
@Slf4j
@Component
public class WxTokenMgr {

    private final WxSettings wxSettings;
    private final RestTemplate restTemplate;

    @Resource
    private Environment env;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    public WxTokenMgr(WxSettings wxSettings, RestTemplateBuilder restTemplateBuilder) {
        this.wxSettings = wxSettings;
        this.restTemplate = restTemplateBuilder.defaultMessageConverters().build();
    }

    /**
     * 获取微信小程序Session Key
     * 缓存三天，其中UnionId可能为空
     */
    public SessionKey getSessionKeyByCode(String code) {
        SessionKey sessionKey = null;
        if (!ArrayUtils.contains(env.getActiveProfiles(), "prod")) {
            SessionKey mockSession = new SessionKey();
            mockSession.setOpenId("oGZUI0egBJY1zhBYw2KhdUfwVJJE");
            mockSession.setSessionKey("tiihtNczf5v6AKRyjwEUhQ==");
            sessionKey = mockSession;
        } else {
            sessionKey = restTemplate.getForObject(WxConstant.SESSION_KEY_URL, SessionKey.class, wxSettings.getAppid(), wxSettings.getAppsecret(), code);
            log.debug("--- sessionKey: [{}]", sessionKey);
            if (sessionKey != null) {
                redisTemplate.opsForValue().set(RedisConstant.MP_CACHE_SESSION_KEY_PREFIX + sessionKey.getOpenId(), sessionKey, 3, TimeUnit.DAYS);
            }
        }

        return sessionKey;
    }

    /**
     * 获取AccessToken
     */
    public AccessToken getToken() {
        AccessToken token;
        Object cacheObj = redisTemplate.opsForValue().get(RedisConstant.MP_ACCESS_TOKEN_CACHE_KEY);
        if (cacheObj == null) {
            token = refreshToken();
        } else {
            AccessToken at = (AccessToken) cacheObj;
            Date expiresDate = DateUtils.addSeconds(at.getCreateTime(), at.getExpiresIn());
            if (new Date().before(expiresDate)) {
                token = at;
            } else {
                token = refreshToken();
            }
        }

        return token;
    }

    /**
     * 刷新AccessToken
     */
    public AccessToken refreshToken() {
        String appId = wxSettings.getAppid();
        log.info("Refreshing token for app [{}] and id [{}]", wxSettings.getAppid(), appId);
        AccessToken newToken = restTemplate.getForObject(WxConstant.ACCESS_TOKEN_URL, AccessToken.class, appId, wxSettings.getAppsecret());
        newToken.setCreateTime(new Date());
        redisTemplate.opsForValue().set(RedisConstant.MP_ACCESS_TOKEN_CACHE_KEY, newToken, 7200, TimeUnit.SECONDS);
        log.debug("new token: {}", newToken.getAccessToken());
        return newToken;
    }
}
